import {AxiosGet} from "./HttpService";
import {defaultLanguage, getLanguageById, getLocale} from "../../i18n/i18n";
import {formatLangStr, formatStr, getObjAttr, importComponent, isJson, objAssign, strToObject, treeMap} from "../utils";
import {Input, InputNumber} from "antd";
import TempInput from "../module/dataForm/TempInput";
import InputModal from "../module/dataForm/InputModal";
import SelectIcon from "../module/dataForm/SelectIcon";
import SelectForm from "../module/dataForm/SelectForm";
import SelectTreeForm from "../module/dataForm/SelectTreeForm";
import SelectColor from "../module/dataForm/SelectColor";
import MultiInput from "../module/dataForm/MultiInput";
import SelectRadio from "../module/dataForm/SelectRadio";
import DefaultValueInput from "../module/dataForm/DefaultValueInput";
import SelectUploadImage from "../module/dataForm/SelectUploadImage";
import SelectUploadFile from "../module/dataForm/SelectUploadFile";
import SelectTransfer from "../module/dataForm/SelectTransfer";
import SelectTreeTransfer from "../module/dataForm/SelectTreeTransfer.tsx";
import SelectDate from "../module/dataForm/SelectDate";
import SelectDateRange from "../module/dataForm/SelectDateRange";
import FileNameInput from "../module/dataForm/FileNameInput";
import InputLocal from "../module/dataForm/InputLocal";
import InputPassword from "../module/dataForm/InputPassword";
import colRenderFnMap from "../module/table/GlobalTableRender.tsx";
import dayjs from "dayjs";

let viewMap: any = {
    table: {},
    form: {},
    formId: {},
    virtually: {}
};

// @ts-ignore
const getViewMapByName: Function = (name: string, type: string = "table") => {
    return viewMap[type][name] ? JSON.parse(JSON.stringify(viewMap[type][name])) : null;
};

// @ts-ignore
const setViewMap: Function = (name: string, data: any, type: string) => {
    viewMap[type][name] = data;
};

const viewUrlMap: any = {
    table: "/sf-drs/platform/view/getSystemTableViewDetails",
    form: "/sf-drs/platform/view/getFormViewDetails"
}

// @ts-ignore
const getView: Function = async (viewName: string, type: string) => {
    let data = getViewMapByName(viewName, type);
    if (!data) {
        let url: string = viewUrlMap[type];
        data = (await AxiosGet(url, {viewName})).data;
        setViewMap(viewName, data, type);
    }
    return data
};

const createColRenderFn = (renderType, renderProps = {}) => {
    const fn = colRenderFnMap[renderType || "defaultValue"];
    if (!fn) {
        throw new Error(`不存在的列render操作: ${renderType}`);
    }
    return fn.bind({renderProps})
}


// @ts-ignore
const getTableViewList: Function = async (data: any, ds: any) => {
    let colData = data.alternativeColumns && data.alternativeColumns.length ? data.alternativeColumns : data.containColumns
    let newColumns: any[] = colData.map((item: any, index: number) => {
        let rgex: any = /,?\s*([^(]*)\(([^\)]*)\)/g,
            cellArr: any[] = rgex.exec(item.config) || [];

        if (cellArr.length < 1 && item.config) {
            cellArr[1] = item.config
        }
        let configItem: any = data.alternativeColumns?.find((node: any) => node.id === item.id) || {};
        let newColumnsItem: any = {
            headerName: getLocale(item.zhCn, item.usEn, item.ptBr),
            headerTooltip: getLocale(item.zhCn, item.usEn, item.ptBr),
            field: formatLangStr(item.field),
            tooltipField: formatLangStr(item.field),
            id: item.id,
            index: configItem.index,
            sortable: item.sortable,
            pinned: item.fixed,
            width: item.width || (index < data.containColumns.length - 1 ? 150 : undefined),
            minWidth: item.width ? (item.width > 150 ? 150 : 100) : 150,
            hide: configItem.visible === "false" || configItem.visible === 0,
            unSortIcon: true,
            cellRenderer: cellArr[1],
            cellRendererParams: {renderProps: strToObject(cellArr[2]), ds},
            oldColumn: {
                ...item,
                parent: {
                    id: data.id,
                    name: data.name
                }
            }
        };
        return newColumnsItem;
    });
    newColumns = newColumns.sort((a, b) => a.index - b.index);
    if (newColumns.length > 0) {
        for (let i = newColumns.length - 1; i >= 0; i--) {
            const column = newColumns[i];
            if (!column.pinned) {
                column.flex = 1;
                break;
            }
        }
    }
    return newColumns;
};

// @ts-ignore
const getTableView: Function = async (view: string, ds: any) => {
    let result: any = await getView(view, "table");
    result.columns = await getTableViewList(result, ds);
    return result;
};


// @ts-ignore
const getFormViewList: Function = async (data: any[] = [], defaultData: any, ds: any) => {
    // 可以配置的输入框组件
    let inputCom: any = {
        DefaultValueInput,
        Input,
        InputNumber,
        InputModal,
        InputLocal,
        InputPassword,
        SelectIcon,
        SelectColor,
        SelectForm,
        SelectRadio,
        SelectTreeForm,
        SelectDate,
        SelectTransfer,
        SelectTreeTransfer,
        SelectDateRange,
        MultiInput,
        FileNameInput,
        SelectUploadImage,
        SelectUploadFile,
    };
    // 记录当前分组id
    let groupId;
    // 视图组合
    let newView: any[] = [], emptyValues: any = {};
    for (let i = 0; i < data.length; i++) {
        let item: any = {...data[i]};
        let {
                viewRule,
                field,
                zhCn,
                usEn,
                ptBrPt,
                defaultValue = "",
                valueField = "",
                valueText = "",
                isNullable,
                isEditable,
                isVisible,
                description
            } = item,
            // 校验规则
            rules = [],
            // description: 其他设置
            otherOption = description ? strToObject(formatStr(description, ds)) : {};

        emptyValues[field] = undefined;
        if (otherOption?.group) {
            groupId = field;
        }
        field = formatLangStr(field);
        valueText = formatLangStr(valueText || "");
        valueField = formatLangStr(valueField || "");
        defaultValue = isJson(defaultValue) ? JSON.parse(defaultValue) : defaultValue;
        if (defaultValue === "newYear") {
            defaultValue = dayjs().year();
        }
        let viewItem: any = {
            field: field || valueField || valueText,
            fieldText: valueText,
            rules,
            title: getLocale(zhCn, usEn, ptBrPt),
            component: null,
            props: {
                disabled: !isEditable
            },
            groupId: groupId,
            required: !isNullable,
            hidden: !isVisible,
            isSubmit: !!(field || valueField),
            mode: (!field && !valueField) ? "show" : "edit",
            ...otherOption
        };
        viewItem.initValue = defaultData ? (defaultData[valueField || field || valueText] !== undefined ? defaultData[valueField || field || valueText] : defaultValue) : defaultValue;
        viewItem.dataSource = {
            value: viewItem.initValue,
            text: defaultData ? (defaultData[valueText || valueField || field] || defaultValue) : defaultValue
        }
        if (data[i].valueText && data[i].valueText.indexOf("|") !== -1) {
            const localValueKey: string[] = data[i].valueText.split("|");
            defaultLanguage.forEach((key: string, index: number) => {
                viewItem.dataSource[key] = defaultData ? defaultData[localValueKey[index]] : defaultValue;
            })
        }
        if (viewRule) {
            let {
                    otherRule,
                    checkRule,
                    errorHintCn = "",
                    errorHintEn = "",
                    inputHintEn = "",
                    inputHintCn = "",
                    lovChildren,
                    maxLength
                }:
                    {
                        otherRule: any,
                        checkRule: any,
                        errorHintCn: string,
                        errorHintEn: string,
                        inputHintCn: string,
                        inputHintEn: string,
                        lovChildren: any[],
                        maxLength: number
                    } = viewRule,
                help: string = getLocale(inputHintCn, inputHintEn),
                errorMsg: string = getLocale(errorHintCn, errorHintEn);

            // 最大长度限制
            if (maxLength) {
                rules.push({
                    max: maxLength,
                    transform: (value: any) => value + "",
                    type: "string",
                    message: getLanguageById("maxLength", {maxLength: maxLength})
                });
            }
            // 正则校验
            if (checkRule) {
                rules.push({pattern: new RegExp(checkRule), message: errorMsg || help});
                // errorMsg 和 help同时存在 提示信息则放在extra中,不然不能同时显示
                if (errorMsg) {
                    viewItem.extra = help;
                }
            }
            // 没有错误提示才能把提示放到help中
            if (!errorMsg && help) {
                viewItem.help = help;
            }
            // 自定义组件
            if (otherRule) {
                //eslint-disable-next-line
                let rgex = /([^(]*)\(([^\)]*)\)/g;
                let arr = rgex.exec(otherRule),
                    // 组件路径或名称
                    comName = otherRule;
                // 判断是否有参数
                if (arr) {
                    comName = arr[1];
                    if (arr[2]) {
                        Object.assign(viewItem.props, strToObject(formatStr(arr[2], ds)));
                    }
                }
                if (otherOption) {
                    viewItem.props = objAssign(viewItem.props, otherOption);
                }
                if (comName === "InputNumber") {
                    viewItem.initValue = viewItem.initValue && !isNaN(viewItem.initValue - 0) ? viewItem.initValue - 0 : viewItem.initValue;
                }
                // 以/开头则代表是路径
                if (comName.startsWith("/")) {
                    viewItem.component = await importComponent(comName);
                } else {
                    // 不是路径则从默认对象中取
                    viewItem.component = getObjAttr(inputCom, comName);
                }
            }
            // 可选项
            if (lovChildren) {
                // 可选项默认以 _options 方式传入组件
                viewItem.props.options = treeMap(lovChildren, (child: any[], item: any) => {
                    return {
                        ...item,
                        label: getLocale(item.zhCn, item.usEn, item.ptBr),
                        value: viewItem.props.isBool ? !!(item.value - 0) : item.value,
                        id: item.id,
                        children: child ? child : undefined
                    }
                });
                if (!viewItem.component) {
                    viewItem.component = inputCom.SelectForm;
                }
            }
        }
        if (!viewItem.component) {
            // 非编辑状态 使用TempInput支持显示值隐藏值
            if (isEditable) {
                viewItem.component = inputCom.Input;
            } else {
                viewItem.component = TempInput;
            }
        }
        newView.push(viewItem);
    }

    return {
        form: newView,
        emptyValues
    };
};

// @ts-ignore
const getFormView: Function = async (view: string, defaultData: any = {}, ds: any, otherRenderFn: any = {}) => {
    let result: any = await getView(view, "form");
    const {form, emptyValues} = await getFormViewList(result.fields, defaultData, ds, otherRenderFn);
    return {
        ...result,
        form,
        emptyValues
    };
};
// @ts-ignore
const getFormViewById: Function = async (viewId: string, defaultData: any = {}, ds: any, otherRenderFn: any = {}) => {
    let result: any;
    let data = getViewMapByName(viewId, "formId");
    if (data) {
        result = data
    } else {
        result = (await AxiosGet("/sf-drs/platform/view/getFormViewDetailsById", {id: viewId})).data;
        setViewMap(viewId, result, "formId");
    }
    const {form, emptyValues} = await getFormViewList(result.fields, defaultData, ds, otherRenderFn);
    return {
        ...result,
        form,
        emptyValues
    };
};

const getFlowFormView: Function = async (view: string, defaultData: any = {}, ds: any, otherRenderFn: any = {}) => {
    let result: any = await getView(view, "flowForm");
    const {form, emptyValues} = await getFormViewList(result.fields, defaultData, ds, otherRenderFn);
    return {
        ...result,
        form,
        emptyValues
    };
};

// @ts-ignore
const getVirtuallyView: Function = async (objectTypeName: string, objectModule: string, defaultData: any = {}, ds: any, otherRenderFn) => {
    let res: any = getViewMapByName(objectTypeName + "-" + objectModule, "virtually");
    if (!res) {
        res = (await AxiosGet("/sf-drs/platform/view/getByObjectTypeAndMoudle", {
            objectTypeName,
            objectModule
        })).data || {};
        setViewMap(objectTypeName + "-" + objectModule, res, "virtually");
    }
    if (res.type === "form") {
        const {form, emptyValues} = await getFormViewList(res.fields, defaultData, ds, otherRenderFn);
        res = {
            ...res,
            form,
            emptyValues
        }
    } else {
        res.columns = await getTableViewList(res, ds);
    }
    return res;
};

const getLovs = async (lovName: string) => {
    const {data = []} = await AxiosGet("/sf-drs/platform/lovs/childs", {name: lovName})
    return data
}

export {
    getLovs,
    getView,
    getTableView,
    getTableViewList,
    getFormView,
    getFormViewList,
    getFormViewById,
    getFlowFormView,
    getVirtuallyView,
    setViewMap
}